/*
 *	secureagent.c
 *  Release $Name: SECUREAGENT-LIB $
 *
 *	JVMTI code for the secure agent library.
 */
/*
 *	Copyright (c) Philipp Haindl, 2011-2012. All Rights Reserved.
 *	The latest version of this code is available at http://www.thinkr.at
 *
 *	This software is open source; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 *	This General Public License does NOT permit incorporating this software
 *	into proprietary programs.
 *
 *	This program is distributed in WITHOUT ANY WARRANTY; without even the
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *	See the GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program; if not, write to the Free Software
 *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *	http://www.gnu.org/copyleft/gpl.html
 */
/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <sys/sem.h>
#include <time.h>
#include "jni.h"
#include "jvmti.h"
#include "utils.h"

void JNICALL vm_init(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
{
    jvmtiError err;
    jobject a;
    jobject b;
    jbyteArray c;
    jint d;
    jint e;

	if (jvmti_version_check(jvmti) == -1)
	{
		(void)fprintf(stderr, "ERROR: Compile Time JVMTI and Run Time JVMTI are incompatible\n");
		(void)close_agent();
	}

}

void JNICALL method_entry_callback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread, jmethodID method)
{
	jvmtiError err;
	char* method_name;
	char* method_sig;
	char* method_generic_ptr;

	jclass clazz;
	char* clazz_signature;
	char* clazz_generic_ptr;

	/* collect some information about the method */
	err = (*jvmti)->GetMethodName(jvmti, method, &method_name, &method_sig, &method_generic_ptr);
	if (err != JVMTI_ERROR_NONE)
	{
		(void)fprintf(stderr, "Unable to get method name (err=%d) !\n", err);
		(void)close_agent();
	}

	err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &clazz);
	if (err != JVMTI_ERROR_NONE)
	{
		(void)fprintf(stderr, "Unable to get declaring class (err=%d) !\n", err);
		(void)close_agent();
	}

	if (strncmp(method_name, "socketWrite0", 12) == 0)
	{
		(void)printf("--> encrypt outbound data\n");
	}
}

void JNICALL method_exit_callback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread, jmethodID method, jboolean was_popped_by_exception, jvalue return_value)
{
	jvmtiError err;
	char* method_name;
	char* method_sig;
	char* method_generic_ptr;

	jclass clazz;
	char* clazz_signature;
	char* clazz_generic_ptr;

	/* collect some information about the method */
	err = (*jvmti)->GetMethodName(jvmti, method, &method_name, &method_sig, &method_generic_ptr);
	if (err != JVMTI_ERROR_NONE)
	{
		(void)fprintf(stderr, "Unable to get method name (err=%d) !\n", err);
		(void)close_agent();
	}

	err = (*jvmti)->GetMethodDeclaringClass(jvmti, method, &clazz);
	if (err != JVMTI_ERROR_NONE)
	{
		(void)fprintf(stderr, "Unable to get declaring class (err=%d) !\n", err);
		(void)close_agent();
	}

	if (strncmp(method_name, "socketRead0", 11) == 0)
	{
		(void)printf("--> decrypt inbound data\n");
	}
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
{
    jint                rc;
    jvmtiError          err;
    jvmtiEventCallbacks callbacks;
    jvmtiEnv           *jvmti;
    int i = 0;

    rc = (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION);
    if (rc != JNI_OK)
    {
    	(void)fprintf(stderr, "ERROR: Unable to create jvmtiEnv, GetEnv failed (err=%d) !\n", rc);
    	(void)close_agent();
    	return -1;
    }

    /* set capabilities */
    if (jvmti_set_capabilities(jvmti) == -1)
    {
    	(void)close_agent();
    }

    /* clear memory */
    (void)memset(&callbacks, 0, sizeof(callbacks));

    /* set callbacks */
    callbacks.VMInit = &vm_init;
	callbacks.MethodEntry = &method_entry_callback;
	callbacks.MethodExit = &method_exit_callback;

    (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));

    /* set notifications */
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_ENTRY, NULL);
    (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL);
	
    return 0;
}

void close_agent()
{
	// release any globally used resources
}

JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm)
{

}
